package virtorina.client.room;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;

import virtorina.client.room.dto.ChatMsgDTO;
import virtorina.client.room.rpc.GWTService4Room;
import virtorina.client.room.rpc.GWTService4RoomAsync;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.FocusEvent;
import com.google.gwt.event.dom.client.FocusHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

public class Chat {

	private final GWTService4RoomAsync sender = GWT
			.create(GWTService4Room.class);
	private final VerticalPanel chatbox = new VerticalPanel();
	private final ScrollPanel ScrlPnl = new ScrollPanel();
	private VerticalPanel chat = new VerticalPanel();
	final TextBox tb = new TextBox();
	private Long lastMessageTime;
	private Long nextMessageTime;
	private Long UserID;
	private String UserName;
	private boolean TimeMsgActive = true;
	private boolean noStart = false;
	private boolean AutoAnsw = false;
	private Virtorina virt;
	private LinkedList<String> UserMsgs = new LinkedList<String>();

	public Long getlastMessageTime() {
		return lastMessageTime;
	}

	public void setlastMessageTime(Long t) {
		this.lastMessageTime = t;
	}
	private Integer ROOM_ID;
	public Chat(int id, Virtorina main) {
		this.virt = main;
		ROOM_ID = id;
		tb.setEnabled(false);
		tb.setStyleName("ChatTextBox");
		tb.addStyleName("gwt-TextBox");
		HorizontalPanel textAbot = new HorizontalPanel();
		textAbot.addStyleName("horPanel");
		final Button autoAns = new Button();
		autoAns.addStyleName("autoAnsBtm");
		autoAns.setText("!");
		textAbot.add(autoAns);
		textAbot.add(tb);
		/*final Button delChat = new Button();
		delChat.addStyleName("delbuttom");
		delChat.setText("clean");
		textAbot.add(delChat);*/
		ScrlPnl.add(chatbox);
		chat.setWidth("100%");
		chat.add(ScrlPnl);
		RootPanel.get("textBox").add(textAbot);
		ScrlPnl.setHeight("492px");
		chatbox.addStyleName("box");
		this.lastMessageTime = 0L;
		this.nextMessageTime = new Date().getTime();
		tb.setText("!<answer>");
		tb.setFocus(true);
		LastTime.scheduleRepeating(5000);
		tb.addBlurHandler(new BlurHandler() {
			@Override
			public void onBlur(BlurEvent event) {
				if (tb.getText().isEmpty()) {
					if (AutoAnsw){
						tb.setText("!<message>");
					}else{
						tb.setText("!<answer>");
					}
				}

			}
		});
		tb.addFocusHandler(new FocusHandler() {

			@Override
			public void onFocus(FocusEvent event) {
				if (!AutoAnsw && tb.getText().equals("!<answer>")) {
					tb.setText("");
				}else if(AutoAnsw && tb.getText().equals("!<message>")) {
					tb.setText("");
				}
			}
		});
		tb.addKeyUpHandler(new PressHandler(tb));
		/*
		delChat.addClickHandler(new ClickHandler() {

			public void onClick(ClickEvent event) {
				chatbox.clear();
				TimeMsgActive = true;
			}
		});*/
		autoAns.addClickHandler(new ClickHandler() {
			
			@Override
			public void onClick(ClickEvent event) {
				AutoAnsw = !AutoAnsw;
				if (AutoAnsw){
					autoAns.addStyleName("answ-input");
					tb.addStyleName("answ-input");
					autoAns.setTitle("To send a message, begin it with the exclamation mark (\"!\") ");
					if (tb.getText().equals("!<answer>")){
						tb.setText("");
					}
					tb.setFocus(true);
				}else{
					autoAns.removeStyleName("answ-input");
					tb.removeStyleName("answ-input");
					autoAns.setTitle("To send a message, begin it with the exclamation mark (\"!\") ");
					if (tb.getText().equals("!<message>")){
						tb.setText("");
					}
					tb.setFocus(true);
				}
				
			}
		});
	}

	VerticalPanel getChat() {
		return chat;
	}

	void startUpdates(Long UserID) {
		this.UserID = UserID;
	}

	void startWriting(String UserName) {
		this.UserName = UserName;
		tb.setEnabled(true);
	}

	void checkNewMessages() {
		sender.getNewMessage(ROOM_ID, new AsyncCallback<ArrayList<ChatMsgDTO>>() {

			@Override
			public void onFailure(Throwable caught) {
				System.out.println("Fail on get msg");

			}

			@Override
			public void onSuccess(ArrayList<ChatMsgDTO> result) {
				for (int i = 0; i < result.size(); i++) {
					if (i != result.size() - 1) {
						nextMessageTime = result.get(i + 1).getDate().getTime();
					} else {
						nextMessageTime = new Date().getTime();
					}
					setNewMessage(result.get(i));
				}
				noStart = true;

			}

		});
	}

	private void setNewMessage(ChatMsgDTO msg) {
		String color = "#3399FF";
		if (msg.getUser().getID().equals(UserID)) {
			if (UserMsgs.contains(msg.getUser().getID() + msg.getMsg())) {
				UserMsgs.remove(msg.getUser() + msg.getMsg());
				return;
			}
			color = "#999999";
		}
		addMessage(msg.getUser().getName(), msg.getUser().getID(),
				msg.getMsg(), color, msg.getDate().getTime());
	}

	String splitter(String Msg) {
		String[] words = Msg.split(" ");
		Msg = "";
		boolean st = false;
		for (String word : words) {
			if (st) {
				Msg += " ";
			}
			while (word.length() > 4) {
				Msg += "<span>" + word.substring(0, 4) + "</span><wbr>";
				word = word.substring(4);
			}
			Msg += word;
			if (!st) {
				st = true;
			}
		}
		return Msg;
	}

	void addMessage(String Name, Long ID, String Msg, String color, long time) {
		final HTML text = new HTML();
		text.addStyleName("msg");
		Msg = ReverseReplace(Msg);
		Msg = splitter(Msg);
		//Msg = HTMLreplace(Msg);
		text.setHTML("<b><span style='padding-left: 5px; color: " + color
				+ "'>" + Name + ":</span></b> " + Msg);
		chatbox.add(text);
		lastMessageTime = time;
		TimeMsgActive = false;
		LastTime.run();
		ScrlPnl.scrollToBottom();
	}

	private Timer LastTime = new Timer() {
		@Override
		public void run() {
			if (!TimeMsgActive) {
				if (noStart) {
					nextMessageTime = new Date().getTime();
				}
				if (nextMessageTime > lastMessageTime + 60000) {
					chatbox.add(new HTML(setLastTime(new Date(lastMessageTime))));
					ScrlPnl.scrollToBottom();
					TimeMsgActive = true;
				}
			}
		}
	};

	private String setLastTime(java.util.Date date) {
		String s = "<span style = \' padding-left: 90px; color: #777\'>\t\t\tSent at ";
		if (date.getHours() < 10) {
			s += "0";
		}
		s += date.getHours() + ":";
		if (date.getMinutes() < 10) {
			s += "0";
		}
		s += date.getMinutes() + "</span>";
		return s;
	}

	void pushAnswer(final String answer) {
		sender.Chkansw(ROOM_ID, answer, new AsyncCallback<Integer>() {

			@Override
			public void onSuccess(Integer result) {
				System.out.println("result "+ result);
				if (result.intValue() > 0) {
					chatbox.add(new HTML("<b  style='color:green'> The answer \""
							+ answer + "\" is correct </b>"));
				} else if (result.intValue() == 0) {
					chatbox.add(new HTML("<b  style='color:blue'> The answer \""
							+ answer + "\" is wrong </b>"));
				}else if (result.intValue() == -1) {
					chatbox.add(new HTML("<b  style='color:blue'> Question not set </b>"));
				}
				ScrlPnl.scrollToBottom();
			}

			@Override
			public void onFailure(Throwable caught) {
				System.out.println("Fail on Check");

			}
		});

	}

	private class PressHandler implements KeyUpHandler {
		TextBox tb;
		boolean isAnsw;

		PressHandler(TextBox tb) {
			this.tb = tb;
		}

		@Override
		public void onKeyUp(KeyUpEvent event) {
			if (tb.getText().length() > 300) {
				tb.addStyleName("long-input");
				tb.setText(tb.getText().substring(0, 300));
				return;
			}
			if (tb.getText().length() == 300) {
				tb.removeStyleName("long-input");
			}
			if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER
					&& tb.getText().length() > 0) {
				String msg = tb.getText();
				if (msg.length() > 300) {
					chatbox.add(new HTML(
							"<b style='color:red'>Very long message </b>"));
					ScrlPnl.scrollToBottom();
					return;
				}
				
				if (!AutoAnsw && msg.charAt(0) != '!' || AutoAnsw && msg.charAt(0) == '!') {
					if (AutoAnsw && msg.charAt(0) == '!'){
						msg = msg.substring(1, msg.length());
					}
					msg = HTMLreplace(msg);
					((GWTService4RoomAsync) GWT.create(GWTService4Room.class))
							.add((long) 0, msg, callback);
					addMessage(UserName, UserID, msg, "#999999",
							new Date().getTime());
					UserMsgs.add(UserID + msg);
					checkNewMessages();
				} else if (AutoAnsw && msg.length() > 0 || !AutoAnsw && msg.charAt(0) == '!' && msg.length() > 1) {
					if (!AutoAnsw){
						msg = msg.substring(1);
					}
					tb.setText(msg);
					pushAnswer(msg);

				}
				tb.setText("");
			}
			if (tb.getText().length() == 1) {
				if (!isAnsw && tb.getText().charAt(0) == '!') {
					isAnsw = true;
					tb.addStyleName("answ-input");
				} else if (isAnsw && tb.getText().charAt(0) != '!') {
					isAnsw = false;
					tb.removeStyleName("answ-input");
				}
			} else if (tb.getText().length() == 0) {
				if (isAnsw) {
					tb.removeStyleName("answ-input");
					isAnsw = false;
				}
			}

		}
	};

	String HTMLreplace(String msg) {
		final StringBuilder result = new StringBuilder();

		for (int i = 0; i < msg.length(); i++) {
			char character = msg.charAt(i);
			if (character == '<') {
				result.append("&lt;");
			} else if (character == '>') {
				result.append("&gt;");
			} else if (character == '&') {
				result.append("&amp;");
			} else if (character == '\"') {
				result.append("&quot;");
			} else if (character == '\t' || character == '\n') {
			} else if (character == '\'') {
				result.append("&#39;");
			} else if (character == '(') {
				result.append("&#40;");
			} else if (character == ')') {
				result.append("&#41;");
			}

			else if (character == '/') {
				result.append("&#47;");
			} else if (character == '[') {
				result.append("&#91;");
			} else if (character == '\\') {
				result.append("&#92;");
			} else if (character == ']') {
				result.append("&#93;");
			} else if (character == '{') {
				result.append("&#123;");
			} else if (character == '}') {
				result.append("&#125;");
			} else {
				result.append(character);
			}
		}
		return result.toString();
	}

	HashMap<String, String> pairs = new HashMap<String, String>();
	{
		pairs.put("&lt;", "<");
		pairs.put("&gt;", ">");
		pairs.put("&amp;", "&");
		pairs.put("&quot;", "\"");
		pairs.put("&#39;", "\'");
		pairs.put("&#40;", "(");
		pairs.put("&#41;", ")");
		pairs.put("&#47;", "/");
		pairs.put("&#91;", "[");
		pairs.put("&#92;", "\\");
		pairs.put("&#93;", "]");
		pairs.put("&#123;", "{");
		pairs.put("&#125;", "}");
	}

	String ReverseReplace(String msg) {
		final StringBuilder result = new StringBuilder(msg);
		int i = 0;
		for (Entry<String, String> pair : pairs.entrySet()) {
			i = result.indexOf(pair.getKey(), 0);
			while (i != -1) {
				result.replace(i, i + pair.getKey().length(), pair.getValue());
				i = result.indexOf(pair.getKey(), i);
			}
		}
		return result.toString();
	}

	final AsyncCallback<Boolean> callback = new AsyncCallback<Boolean>() {

		@Override
		public void onFailure(Throwable caught) {
			System.out.println("Connection fail!");
		}

		@Override
		public void onSuccess(Boolean result) {
		}
	};
}
